package cn.amebius.simpledocker.service.impl;

import cn.amebius.simpledocker.config.DockerFactory;
import cn.amebius.simpledocker.entity.dto.DockerContainerDto;
import cn.amebius.simpledocker.entity.model.ContainerInfoModel;
import cn.amebius.simpledocker.entity.model.DockerClientModel;
import cn.amebius.simpledocker.entity.model.DockerContainerModel;
import cn.amebius.simpledocker.exception.DockerErrorException;
import cn.amebius.simpledocker.service.ContainerService;
import cn.hutool.core.date.DateTime;
import cn.hutool.core.date.DateUtil;
import com.github.dockerjava.api.DockerClient;
import com.github.dockerjava.api.command.InspectContainerResponse;
import com.github.dockerjava.api.model.*;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.Set;


/**
 * 容器服务实现类
 * @author 阿伟
 * @date 2023/8/30 20:45
 */

@Slf4j
@Service
public class ContainerServiceImpl implements ContainerService {

    @Autowired
    DockerFactory dockerFactory;
    @Override
    public DockerContainerDto getAll() {
        DockerContainerDto dcd = new DockerContainerDto();
        ArrayList<DockerContainerModel> containerModels = new ArrayList<>();
        Integer total = 0, running = 0, stopped = 0, paused = 0;
        Map<Integer, DockerClientModel> cg = dockerFactory.getClientGroup();
        Set<Integer> keys = cg.keySet();
        for (Integer key : keys) {
            DockerClientModel dcm = cg.get(key);
            if (!dcm.getAlive()) {
                continue;
            }
            DockerClient dc = dcm.getDockerClient();
            List<Container> containers = dc.listContainersCmd().withShowAll(true).exec();
            for (Container container : containers) {
                total++;
                DockerContainerModel model = new DockerContainerModel();
                model.setKey(key);
                model.setId(dcm.getId());
                model.setContainer(container);
                model.setName(dcm.getDocker().getName());
                containerModels.add(model);
            }
        }
        dcd.setTotal(total);
        dcd.setRunning(running);
        dcd.setStopped(stopped);
        dcd.setPaused(paused);
        dcd.setContainers(containerModels);
        return dcd;
    }

    @Override
    public void startContainer(Integer key, String id) {
        DockerClientModel dcm = dockerFactory.getByKey(key);
        DockerClient dc = dcm.getDockerClient();
        try {
            dc.startContainerCmd(id).exec();
            dockerFactory.updateInfo(dcm);
        } catch (Exception e) {
            throw new DockerErrorException("Docker异常：启动容器失败");
        }

    }

    @Override
    public void stopContainer(Integer key, String id) {
        DockerClientModel dcm = dockerFactory.getByKey(key);
        DockerClient dc = dcm.getDockerClient();
        try {
            dc.stopContainerCmd(id).exec();
            dockerFactory.updateInfo(dcm);
        } catch (Exception e) {
            throw new DockerErrorException("Docker异常：停止容器失败");
        }
    }

    @Override
    public void pauseContainer(Integer key, String id) {
        DockerClientModel dcm = dockerFactory.getByKey(key);
        DockerClient dc = dcm.getDockerClient();
        try {
            dc.pauseContainerCmd(id).exec();
            dockerFactory.updateInfo(dcm);
        } catch (Exception e) {
            throw new DockerErrorException("Docker异常：暂停容器失败");
        }
    }

    @Override
    public void unpauseContainer(Integer key, String id) {
        DockerClientModel dcm = dockerFactory.getByKey(key);
        DockerClient dc = dcm.getDockerClient();
        try {
            dc.unpauseContainerCmd(id).exec();
            dockerFactory.updateInfo(dcm);
        } catch (Exception e) {
            throw new DockerErrorException("Docker异常：取消暂停容器失败");
        }
    }

    @Override
    public ContainerInfoModel getInfoById(Integer key, String id) {
        DockerClientModel dcm = dockerFactory.getByKey(key);
        DockerClient dc = dcm.getDockerClient();
        try {
            InspectContainerResponse icr = dc.inspectContainerCmd(id).exec();
            ContainerInfoModel cim = new ContainerInfoModel();
            cim.setName(icr.getName().substring(1));
            cim.setStatus(icr.getState().getStatus());
            ContainerConfig config = icr.getConfig();
            String[] cmd = config.getCmd();
            cim.setCmd(paramsToString(cmd));
            String[] entrypoint = config.getEntrypoint();
            cim.setEntrypoint(paramsToString(entrypoint));
            String[] env = config.getEnv();
            cim.setEnv(paramsToString(env));
            cim.setHostName(config.getHostName());
            cim.setImage(config.getImage());
            cim.setWorkingData(config.getWorkingDir());
            System.out.println(1);
            DateTime parse = DateUtil.parse(icr.getCreated().substring(0, icr.getCreated().length() - 6));
            cim.setCreateTime(parse.toString());
            HostConfig hostConfig = icr.getHostConfig();
            Bind[] binds = hostConfig.getBinds();
            String[] bindStr = new String[binds.length];
            for (int i = 0; i < binds.length; i++) {
                bindStr[i] = binds[i].getPath() + ":" + binds[i].getVolume() + ":" + binds[i].getAccessMode();
            }
            cim.setHostBinds(paramsToString(bindStr));

            Ports portBindings = hostConfig.getPortBindings();
            Map<ExposedPort, Ports.Binding[]> bindings = portBindings.getBindings();
            Set<ExposedPort> exposedPorts = bindings.keySet();
            int size = exposedPorts.size();
            StringBuffer sb = new StringBuffer();
            for (ExposedPort exposedPort : exposedPorts) {
                int port = exposedPort.getPort();
                String scheme = exposedPort.getScheme();
                if (--size != 0) {
                    sb.append(port);
                    sb.append("(" + scheme + ");");
                } else {
                    sb.append(port);
                    sb.append("(" + scheme + ")");
                }
            }
            cim.setPorts(sb.toString());
            return cim;
        } catch (Exception e) {
            System.out.println(e.getMessage());
            throw new DockerErrorException("Docker异常：查询container信息错误");
        }
    }

    @Override
    public void renameContainer(Integer key, String id, String name) {
        DockerClientModel dcm = dockerFactory.getByKey(key);
        DockerClient dc = dcm.getDockerClient();
        try {
            dc.renameContainerCmd(id).withName(name).exec();
            dockerFactory.updateInfo(dcm);
        } catch (Exception e) {
            throw new DockerErrorException("Docker异常：重命名容器失败");
        }

    }

    @Override
    public void removeContainer(Integer key, String id, Boolean force, Boolean removeVolume) {
        DockerClientModel dcm = dockerFactory.getByKey(key);
        DockerClient dc = dcm.getDockerClient();
        try {
            dc.removeContainerCmd(id)
                    .withForce(force)
                    .withRemoveVolumes(removeVolume)
                    .exec();
        } catch (Exception e) {
            throw new DockerErrorException("Docker异常：删除容器错误");
        }
    }


    private String paramsToString(String[] args) {
        if (args == null) {
            return "无";
        }
        StringBuffer sb = new StringBuffer();
        for (int i = 0 ; i < args.length; i ++) {
            sb.append(args[i]);
            if (i < args.length - 1) {
                sb.append(";");
            }
        }
        return sb.toString();
    }


}
